package com.chukun.multi.producerconsumer;

import com.chukun.multi.twophase.AbstractTerminatableThread;

import java.io.*;
import java.text.Normalizer;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * @author chukun
 *  生产者
 */
public class AttachmentProcessor {

    private final String ATTACHMENT_STORE_BASE_DIR = "/home/chukun/tmp/attachments/";

    private final ProductChannel<File> channel = new BlockingQueueProductChannel<File>(new ArrayBlockingQueue<>(1024));

    // 消费者
    private final AbstractTerminatableThread indexThread = new AbstractTerminatableThread() {
        @Override
        protected void doRun() throws Exception {
            File file = null;
            file = channel.take();
            try{
                indexFile(file);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                indexThread.terminationToken.reservations.decrementAndGet();
            }
        }

        /**
         * 索引文件
         * @param file
         */
        private void indexFile(File file) {
            // 省略实现代码

            // 模拟文件生成耗时
            Random rnd = new Random();
            try {
                Thread.sleep(rnd.nextInt(1000));
            } catch (InterruptedException e) {
            }
        }
    };

    public void init(){
        indexThread.start();
    }

    public void shutdown(){
        indexThread.terminate();
    }

    /**
     * 保存文件
     * @param in
     * @param documentId
     * @param originalFileName
     * @throws IOException
     */
    public void saveAttachment(InputStream in,String documentId,String originalFileName) throws IOException {
        File file = saveAsFile(in,documentId,originalFileName);
        try{
            channel.put(file);
        }catch (InterruptedException e) {
            ;
        }
        indexThread.terminationToken.reservations.incrementAndGet();
    }

    /**
     * 保存文件
     * @param in
     * @param documentId
     * @param originalFileName
     * @return
     * @throws IOException
     */
    private File saveAsFile(InputStream in, String documentId, String originalFileName) throws IOException {
        String dirName = ATTACHMENT_STORE_BASE_DIR+documentId;
        File dir = new File(dirName);
        dir.mkdirs();
        File file = new File(dirName+"/"+ Normalizer.normalize(originalFileName, Normalizer.Form.NFC));

        // 防止目录跨越攻击
        if (!dirName.equals(file.getCanonicalFile().getParent())) {
            throw new SecurityException("invalid originalFileName : "+originalFileName);
        }
        BufferedOutputStream bos = null;
        BufferedInputStream bis = new BufferedInputStream(in);
        byte[] buf = new byte[1024];
        int len = -1;
        try{
            bos = new BufferedOutputStream(new FileOutputStream(file));
            while ((len = bis.read(buf)) > 0 ) {
                bos.write(buf,0,len);
            }
            bos.flush();
        }finally {
            bis.close();
            bos.close();
        }
        return file;
    }
}
